<template>
  <el-row :gutter="8" class="row-box">
    <el-col :span="5">
      <AppTitleBox class="app-title-box" title="菜单维护">
        <template #button>
          <el-button @click="createMenu(0)" link type="primary">添加</el-button>
        </template>

        <div class="tree-box" ref="treeBox" v-loading="menuLoading">
          <el-tree
            draggable
            :data="menu.tree"
            node-key="id"
            :props="{ children: 'children' }"
            @node-click="clickMenu"
            :style="'height: ' + treeHeight + 'px'"
            @node-expand="handleNodeExpand"
            @node-collapse="handleNodeCollapse"
            :default-expanded-keys="defaultExpandIds"
            @node-drop="dropMenu"
          >
            <template #default="{ data }">
              <div class="tree-node">
                <div class="dropdownMenu">
                  <div class="name">
                    {{ data.label }}
                  </div>
                  <div class="icon-box" @click.stop>
                    <el-dropdown trigger="click">
                      <img
                        class="el-dropdown-link"
                        src="@/assets/images/menu.svg"
                      />

                      <template #dropdown>
                        <el-dropdown-menu>
                          <el-dropdown-item @click="createMenu(data.id)"
                            >添加子菜单</el-dropdown-item
                          >
                          <el-dropdown-item @click="updateMenu(data)"
                            >编辑菜单</el-dropdown-item
                          >
                          <el-dropdown-item @click="deleteMenu(data.id)"
                            >删除菜单</el-dropdown-item
                          >
                        </el-dropdown-menu>
                      </template>
                    </el-dropdown>
                  </div>
                </div>
              </div>
            </template>
          </el-tree>
        </div>
      </AppTitleBox>
    </el-col>
    <el-col :span="19">
      <AppTitleBox class="app-title-box" title="菜单按钮列表">
        <div class="fullHeight" v-show="button.currentMenuId != 0">
          <div class="btns">
            <el-button @click="createButton" type="primary">添加</el-button>
            {{ activeGroundChildNode }}
          </div>
          <AppPageTable
            stripe
            :data="button.data"
            @change="getList()"
            :autostyle="'height: calc(100% - 40px);'"
            :option="button.option"
            :isPagination="true"
          >
            <el-table-column prop="title" label="按钮名称"></el-table-column>
            <el-table-column
              prop="linkUrl"
              label="后台接口Url"
            ></el-table-column>
            <el-table-column prop="permission" label="权限"> </el-table-column>
            <el-table-column label="操作">
              <template #default="scope">
                <el-button @click="editButton(scope.row)" link type="primary"
                  >编辑</el-button
                >
                <el-button
                  @click="deleteButton(scope.row.id)"
                  link
                  type="danger"
                  >删除</el-button
                >
              </template>
            </el-table-column>
          </AppPageTable>
        </div>
      </AppTitleBox>
    </el-col>
  </el-row>

  <!-- 菜单编辑/创建 弹窗 -->
  <el-dialog
    :title="menu.isCreate ? '创建菜单' : '编辑菜单'"
    v-model="menu.show"
    width="500px"
  >
    <el-form
      :model="menu.editMenu"
      :rules="menu.rule"
      ref="menuForm"
      label-width="110px"
      class="El-form"
    >
      <el-form-item label="菜单图标" prop="icon">
        <el-popover
          placement="bottom"
          :width="358"
          ref="popoverRef"
          @hide="popoverHide"
        >
          <el-input
            v-model="iconSearchText"
            placeholder="请输入图标名称"
            clearable
            @input="changeIconList"
          >
            <template #prefix>
              <el-icon class="el-input__icon"><search /></el-icon>
            </template>
          </el-input>
          <div class="spaceborder"></div>
          <el-scrollbar :height="200">
            <div class="iconBox">
              <div
                class="iconitem"
                v-for="name in iconSearchList"
                :key="name"
                @click="iconClick(name)"
              >
                <component
                  :is="name"
                  style="width: 16px; height: 30px"
                ></component>
                <span>{{ name }}</span>
              </div>
            </div>
          </el-scrollbar>
          <template #reference>
            <el-input
              v-model="menu.editMenu.icon"
              readonly
              placeholder="点击选择图标"
            >
              <template #prefix>
                <el-icon class="el-input__icon"><search /></el-icon>
              </template>
            </el-input>
          </template>
        </el-popover>
      </el-form-item>

      <el-form-item label="菜单名称" prop="title">
        <el-input v-model="menu.editMenu.title"></el-input>
      </el-form-item>

      <el-form-item label="路径" prop="path">
        <el-input v-model="menu.editMenu.path"></el-input>
      </el-form-item>

      <el-form-item label="备注" prop="Remark">
        <el-input v-model="menu.editMenu.Remark" type="textarea"></el-input>
      </el-form-item>

      <!-- <el-form-item label="是否为新标签页" prop="IsExternalLink">
        <el-checkbox v-model="menu.editMenu.IsExternalLink"
          >新开标签页</el-checkbox
        >
      </el-form-item> -->
      <el-form-item label="是否隐藏" prop="hidden">
        <el-switch v-model="menu.editMenu.hidden">
        </el-switch>
      </el-form-item>
      <el-form-item label="排序号" prop="sort">
        <el-input v-model.number="menu.editMenu.sort"></el-input>
      </el-form-item>
    </el-form>

    <template #footer>
      <span class="dialog-footer">
        <el-button @click="menu.show = false">取 消</el-button>
        <el-button type="primary" @click="submitMenu">保 存</el-button>
      </span>
      <div></div>
    </template>
  </el-dialog>

  <!-- 按钮编辑/创建 弹窗 -->
  <el-dialog
    :title="button.isCreate ? '创建按钮' : '编辑按钮'"
    v-model="button.show"
    width="500px"
    :close-on-click-modal="false"
  >
    <el-form
      :model="button.editButton"
      :rules="button.rule"
      ref="buttonForm"
      label-width="130px"
      class="El-form"
    >
      <el-form-item label="按钮名称" prop="title">
        <el-input v-model="button.editButton.title"></el-input>
      </el-form-item>

      <el-form-item label="后台接口地址" prop="linkUrl">
        <el-input v-model="button.editButton.linkUrl"></el-input>
      </el-form-item>

      <el-form-item label="权限" prop="permission">
        <el-input v-model="button.editButton.permission"></el-input>
      </el-form-item>
    </el-form>

    <template #footer>
      <span class="dialog-footer">
        <el-button @click="button.show = false">取 消</el-button>
        <el-button type="primary" @click="submitButton">保 存</el-button>
      </span>
      <div></div>
    </template>
  </el-dialog>
</template>

<script>
import { defineComponent, nextTick } from "vue";
import AppTitleBox from "@/components/AppTitleBox.vue";
import * as ElIcons from "@element-plus/icons";
import AppPageTable, { useTableOption } from "@/components/AppPageTable2";

export default defineComponent({
  components: {
    AppTitleBox,
    ElIcons,
    AppPageTable,
  },
  data() {
    return {
      defaultExpandIds: [], // 这里存放要默认展开的节点 id
      /**
       * 菜单维护
       */
      activeName: "menuEdit",

      // 菜单相关
      menu: {
        // 是否是创建菜单
        isCreate: false,
        // 显示dialog
        show: false,
        // 菜单树
        tree: [],
        // menu信息
        editMenu: {
          // id
          Id: 0,
          // 菜单图标
          icon: "",
          // 菜单名称
          title: "",
          // 父级id
          parentId: 0,
          // 路径/外部链接
          path: "",
          // 是否为新开标签页
          hidden: false,
          // 备注
          Remark: "",
          // 排序号
          sort: 0,
        },
        rule: {
          title: [
            { required: true, message: "请输入菜单名称", trigger: "blur" },
          ],
          path: [{ required: true, message: "请输入路径", trigger: "blur" }],
        },
      },
      button: {
        // 当前菜单Id
        currentMenuId: 0,
        // 按钮数据
        data: [],
        option: useTableOption(),
        // 是否为新建
        isCreate: false,
        // 是否显示dialog
        show: false,
        // 正在创建/更新的按钮
        editButton: {
          Id: 0,
          parentId: 0,
          // 名称
          title: "",
          // 后台Url
          linkUrl: "",
          // 权限
          permission: "",

          type: 3,
          cache: false,
          hidden: false,
          iframe: false,
          sort: 1,
        },
        // 验证
        rule: {
          title: [
            { required: true, message: "请输入按钮名称", trigger: "change" },
          ],
          linkUrl: [
            { required: true, message: "请输入接口地址", trigger: "change" },
          ],
          permission: [
            { required: true, message: "请输入权限", trigger: "change" },
          ],
        },
      },
      treeHeight: 0,
      buttonTableLoading: false,
      activeGroundChildNode: "",
      iconSearchText: "",
      iconList: [],
      iconSearchList: [],
      visible: false,
      menuLoading: false,
    };
  },
  methods: {
    // 树节点展开
    handleNodeExpand(data) {
      // 保存当前展开的节点
      let flag = false;
      this.defaultExpandIds.some((item) => {
        if (item === data.id) {
          // 判断当前节点是否存在， 存在不做处理
          flag = true;
          return true;
        }
      });
      if (!flag) {
        // 不存在则存到数组里
        this.defaultExpandIds.push(data.id);
      }
    },
    // 树节点关闭
    handleNodeCollapse(data) {
      // 删除当前关闭的节点
      this.defaultExpandIds.some((item, i) => {
        if (item === data.id) {
          this.defaultExpandIds.splice(i, 1);
        }
      });
      this.removeChildrenIds(data); // 这里主要针对多级树状结构，当关闭父节点时，递归删除父节点下的所有子节点
    },
    // 删除树子节点
    removeChildrenIds(data) {
      const ts = this;
      if (data.children) {
        data.children.forEach(function (item) {
          const index = ts.defaultExpandIds.indexOf(item.id);
          if (index > 0) {
            ts.defaultExpandIds.splice(index, 1);
          }
          ts.removeChildrenIds(item);
        });
      }
    },

    /**
     * 创建菜单
     * parentId 父级id  顶级 = 0
     */
    createMenu(parentId) {
      this.menu.isCreate = true;
      this.menu.editMenu = {
        // id
        Id: 0,
        // 菜单图标
        icon: "",
        // 菜单名称
        title: "",
        // 父级id
        parentId: parentId,
        // 路径/外部链接
        path: "",
        // 是否为新开标签页
        IsExternalLink: false,
        // 备注
        Remark: "",
        // 排序号
        sort: 1,
        //1 菜单 2 子菜单 3按钮
        type: 1,
        iframe: false,
        hidden: false,
        cache: false,
      };
      this.menu.show = true;
    },

    /**
     * 更新菜单
     */
    updateMenu(data) {
      this.menu.isCreate = false;
      this.menu.editMenu = JSON.parse(JSON.stringify(data));
      this.menu.show = true;
    },

    /**
     * 删除菜单
     */
    async deleteMenu(id) {
      let res = await this.$http.post("/api/menu/delete", { idArray: [id] });
      if (res.status) {
        this.$message.success("删除成功");
        this.loadMenuTree();
      } else {
        this.$message.error(res.Message);
      }
    },

    /**
     * 提交菜单
     */
    async submitMenu() {
      // 检查form
      let validateRes = await this.$refs.menuForm.validate();
      if (!validateRes) {
        this.$message.warning("请填写所有项");
        return;
      }

      let res = null;
      if (this.menu.isCreate) {
        res = await this.$http.post("/api/menu/create", this.menu.editMenu);
      } else {
        res = await this.$http.post("/api/menu/edit", this.menu.editMenu);
      }
      if (res.status) {
        this.$message.success("保存成功");
        this.menu.show = false;
        this.loadMenuTree();
      } else {
        this.$message.error(res.message ?? "保存失败");
      }
    },

    /**
     * 加载
     */
    async loadMenuTree() {
      let res = await this.$http.get("/api/menu/all?pid=0");
      this.menu.tree = res;
    },

    defaultExpandMenu() {
      this.$http.get("/api/menu/all?pid=0").then((res) => {
        this.menu.tree = res;
        let forData = {
          active: [],
          extends: [],
        };
        forData = this.getFirstChild(res[0], forData);
        this.loadButtons(forData.extends[forData.extends.length - 1]);
        this.defaultExpandIds = forData.extends.slice(0, -1);
        this.activeGroundChildNode = forData.active.join("/");
      });
    },

    getFirstChild(node, forData) {
      forData.extends.push(node.id);
      forData.active.push(node.title);
      if (node.children[0]) {
        forData = this.getFirstChild(node.children[0], forData);
      }
      return forData;
    },

    /**
     * 点击菜单
     */
    clickMenu(menu, node) {
      if (menu.children.length == 0) {
        this.loadButtons(menu.id);
        this.activeGroundChildNode = this.getAncestors(node);
      }
    },

    /**
     * 点击节点获取所有父节点和当前节点名称
     */
    getAncestors(node) {
      const ancestors = [];
      let current = node;

      while (current) {
        ancestors.unshift(current.label); // 将祖先节点的名称添加到数组的开头
        current = current.parent; // 移动到父节点
      }
      return ancestors.join("/").substring(1);
    },

    /**
     * 加载按钮
     */
    loadButtons(menuId) {
      this.button.option.loading = true;
      this.$http
        .get("/api/menu/lazy", {
          pid: menuId,
        })
        .then((res) => {
          this.button.option.loading = false;
          this.button.currentMenuId = menuId;
          this.button.data = res;
        });
    },

    /**
     * 创建按钮
     */
    createButton() {
      this.button.isCreate = true;
      this.button.editButton = {
        Id: 0,
        parentId: this.button.currentMenuId,
        // 名称
        title: "",
        // 后台Url
        linkUrl: "",
        // 权限
        permission: "",

        type: 3,
        cache: false,
        hidden: false,
        iframe: false,
        sort: 1,
      };
      this.button.show = true;
      nextTick(() => {
        this.$refs.buttonForm.resetFields();
      });
    },

    /**
     * 编辑按钮
     */
    editButton(data) {
      this.button.isCreate = false;
      this.button.editButton = JSON.parse(JSON.stringify(data));
      this.button.show = true;
    },

    /**
     * 删除按钮
     */
    async deleteButton(id) {
      let res = await this.$http.post("/api/menu/delete", { idArray: [id] });
      if (res.status) {
        this.$message.success(res.message ?? "删除成功");
        this.loadButtons(this.button.currentMenuId);
      } else {
        this.$message.error(res.message);
      }
    },

    /**
     * 提交按钮
     */
    async submitButton() {
      // 检查form
      let validateRes = await this.$refs.buttonForm.validate();
      if (!validateRes) {
        this.$message.warning("请填写所有项");
        return;
      }

      let res = null;
      let url = null;

      if (this.button.isCreate) {
        url = "/api/menu/create";
      } else {
        url = "/api/menu/edit";
      }
      this.$http
        .post(url, this.button.editButton)
        .then((res) => {
          if (res.status) {
            this.$message.success(res.message ?? "保存成功");
            this.button.show = false;
            this.loadButtons(this.button.currentMenuId);
          } else {
            this.$message.error(res.message ?? "保存失败");
            return;
          }
        })
        .catch((err) => {
          console.log(err);
        });
    },
    getData() {
      var _this = this;
      for (const name in ElIcons) {
        _this.iconList.push(name);
      }
      _this.iconSearchList = _this.iconList;
    },
    iconClick(name) {
      this.menu.editMenu.icon = name;
      this.$refs.popoverRef.hide();
    },
    changeIconList() {
      var arr = [];
      if (!this.iconSearchText) {
        this.iconSearchList = this.iconList;
        return;
      }
      arr = this.iconList.filter((item) => {
        return (
          item.toLowerCase().indexOf(this.iconSearchText.toLowerCase()) != -1
        );
      });
      this.iconSearchList = arr;
    },
    popoverHide() {
      this.iconSearchText = "";
      this.iconSearchList = this.iconList;
    },
    dropMenu(node, beNode, place, event) {
      let changeParentID = 0;
      if (place == "inner") {
        changeParentID = beNode.data.id;
        this.menuLoading = true;
      } else {
        if (beNode.data.parentId == undefined) {
          changeParentID = node.data.id;
          this.menuLoading = true;
        } else {
          if (node.data.parentId != beNode.data.parentId) {
            changeParentID = beNode.data.parentId;
            this.menuLoading = true;
          } else {
            return;
          }
        }
      }
      node.data.parentId = changeParentID;
      this.$http.post("/api/menu/edit", node.data).then((res) => {
        this.menuLoading = false;
      });
    },
  },
  watch: {
    "menu.show"(newVal) {
      if (!newVal) {
        this.menu.editMenu = {
          // id
          Id: 0,
          // 菜单图标
          icon: "",
          // 菜单名称
          title: "",
          // 父级id
          parentId: 0,
          // 路径/外部链接
          path: "",
          // 是否为新开标签页
          IsExternalLink: false,
          // 备注
          Remark: "",
          // 排序号
          sort: 1,
          //1 菜单 2 子菜单 3按钮
          type: 1,
          iframe: false,
          hidden: false,
          cache: false,
        };
        this.$nextTick(() => {
          this.$refs.menuForm.clearValidate();
        });
      }
    },
  },
  created() {
    this.defaultExpandMenu();
  },
  mounted() {
    this.treeHeight = window.getComputedStyle(this.$refs.treeBox).height;
    this.getData();
  },
});
</script>

<style lang="scss" scoped>
.row-box {
  height: 100%;
  box-sizing: border-box;

  .el-col {
    height: 100%;
    box-sizing: border-box;
  }
}

.app-title-box {
  height: 100%;
  box-sizing: border-box;
}

.tree-node {
  width: 100%;
}

.btns {
  padding-bottom: 8px;
}

.dropdownMenu {
  display: flex;
  justify-content: space-between;
}

.dropdownMenu:hover .el-dropdown-link {
  opacity: 1;
}

.name {
  margin-right: auto;
}

.el-dropdown-link {
  margin-right: 5px;
  // margin-top: 5px;
  opacity: 0;
}
.tree-box {
  height: 100%;
}

.fullHeight {
  height: 100%;
}

.tableBox {
  height: calc(100% - 52px);
}

.El-form {
  :deep(.el-form-item__label) {
    display: block;
    text-align: right;
  }
}

.icon-box {
  display: flex;
  justify-content: center;
}
:deep(.el-input__icon) {
  margin-top: 3px;
}
:deep(.el-input__clear) {
  margin-top: 0px;
}
.spaceborder {
  height: 8px;
}
.iconBox {
  width: 100%;
  height: 100%;
  display: flex;
  flex-wrap: wrap;
}
.iconitem {
  height: 30px;
  width: 33%;
  display: flex;
  align-items: center;
  cursor: pointer;
  span {
    font-size: 12px;
    margin-left: 4px;
  }
}
</style>
